package com.christina.engine.response.decorator.impl;

import com.christina.engine.response.decorator.ResponseDecorator;
import com.christina.engine.response.decorator.ResponseGenerator;
import com.christina.engine.response.model.ResponseContext;
import com.christina.engine.response.model.ResponseResult;
import org.springframework.stereotype.Component;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 缓存响应装饰器
 * 为响应生成添加缓存功能，提升性能
 * 
 * @author Christina
 */
@Component
public class CachingResponseDecorator extends ResponseDecorator {
    
    private static final String DECORATOR_NAME = "CachingDecorator";
    private static final int PRIORITY = 200; // 高优先级，在日志之后执行
    
    // 缓存存储
    private final ConcurrentMap<String, CacheEntry> cache = new ConcurrentHashMap<>();
    
    // 缓存配置
    private long defaultTtlMinutes = 30; // 默认缓存30分钟
    private int maxCacheSize = 1000; // 最大缓存条目数
    private boolean enableCache = true; // 是否启用缓存
    
    public CachingResponseDecorator(ResponseGenerator wrapped) {
        super(wrapped, DECORATOR_NAME, PRIORITY);
    }
    
    // 无参构造函数，用于Spring注入
    public CachingResponseDecorator() {
        super(null, DECORATOR_NAME, PRIORITY);
    }
    
    @Override
    protected ResponseResult decorate(ResponseContext context, ResponseResult result) {
        return doDecorate(result, context);
    }
    
    @Override
    protected ResponseResult doDecorate(ResponseResult result, ResponseContext context) {
        if (!enableCache) {
            return result;
        }
        
        String cacheKey = generateCacheKey(context);
        
        // 尝试从缓存获取
        CacheEntry cachedEntry = cache.get(cacheKey);
        if (cachedEntry != null && !cachedEntry.isExpired()) {
            logger.debug("缓存命中 - RequestId: {}, CacheKey: {}", context.getRequestId(), cacheKey);
            
            ResponseResult cachedResult = cachedEntry.getResult();
            
            // 更新缓存相关的元数据
            ResponseResult resultWithCacheInfo = ResponseResult.builder()
                    .content(cachedResult.getContent())
                    .responseType(cachedResult.getResponseType())
                    .success(cachedResult.isSuccess())
                    .errorMessage(cachedResult.getErrorMessage())
                    .generatedTime(cachedResult.getGeneratedTime())
                    .generationDurationMs(0L) // 缓存命中，生成时间为0
                    .generatorName(cachedResult.getGeneratorName())
                    .qualityScore(cachedResult.getQualityScore())
                    .metadata(cachedResult.getMetadata())
                    .build();
            
            resultWithCacheInfo.addMetadata("cache_hit", true);
            resultWithCacheInfo.addMetadata("cache_key", cacheKey);
            resultWithCacheInfo.addMetadata("cached_at", cachedEntry.getCachedAt());
            resultWithCacheInfo.addMetadata("cache_ttl_minutes", cachedEntry.getTtlMinutes());
            
            return resultWithCacheInfo;
        }
        
        // 缓存未命中，生成新的响应
        logger.debug("缓存未命中 - RequestId: {}, CacheKey: {}", context.getRequestId(), cacheKey);
        
        // 如果结果成功且可缓存，则存入缓存
        if (result.isSuccess() && isCacheable(context, result)) {
            long ttl = determineTtl(context, result);
            CacheEntry entry = new CacheEntry(result, ttl);
            
            // 检查缓存大小限制
            if (cache.size() >= maxCacheSize) {
                evictOldestEntries();
            }
            
            cache.put(cacheKey, entry);
            
            logger.debug("响应已缓存 - RequestId: {}, CacheKey: {}, TTL: {}分钟", 
                    context.getRequestId(), cacheKey, ttl);
        }
        
        // 添加缓存相关的元数据
        result.addMetadata("cache_hit", false);
        result.addMetadata("cache_key", cacheKey);
        result.addMetadata("cacheable", isCacheable(context, result));
        
        return result;
    }
    
    @Override
    protected boolean shouldDecorate(ResponseContext context) {
        // 只对特定类型的响应进行缓存
        return enableCache && isCacheableContext(context);
    }
    
    /**
     * 生成缓存键
     * 
     * @param context 响应上下文
     * @return 缓存键
     */
    private String generateCacheKey(ResponseContext context) {
        StringBuilder keyBuilder = new StringBuilder();
        
        // 基于用户输入、意图类型和用户ID生成键
        keyBuilder.append("user:").append(context.getUserId());
        
        if (context.getRecognizedIntent() != null) {
            keyBuilder.append(":intent:").append(context.getRecognizedIntent().getType());
        }
        
        keyBuilder.append(":input:").append(context.getUserInput());
        
        // 添加响应类型
        if (context.getResponseType() != null) {
            keyBuilder.append(":type:").append(context.getResponseType());
        }
        
        // 添加用户偏好的影响
        if (context.getUserPreferences() != null && !context.getUserPreferences().isEmpty()) {
            keyBuilder.append(":prefs:").append(context.getUserPreferences().hashCode());
        }
        
        // 生成MD5哈希以确保键的长度合理
        return generateMD5Hash(keyBuilder.toString());
    }
    
    /**
     * 生成MD5哈希
     * 
     * @param input 输入字符串
     * @return MD5哈希值
     */
    private String generateMD5Hash(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(input.getBytes());
            
            StringBuilder sb = new StringBuilder();
            for (byte b : hashBytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
            
        } catch (NoSuchAlgorithmException e) {
            // 如果MD5不可用，使用简单的哈希
            return String.valueOf(input.hashCode());
        }
    }
    
    /**
     * 判断上下文是否可缓存
     * 
     * @param context 响应上下文
     * @return 是否可缓存
     */
    private boolean isCacheableContext(ResponseContext context) {
        // 不缓存包含敏感信息的请求
        if (context.getUserInput() != null) {
            String input = context.getUserInput().toLowerCase();
            if (input.contains("密码") || input.contains("password") || 
                input.contains("token") || input.contains("secret")) {
                return false;
            }
        }
        
        // 不缓存实时性要求高的请求
        if (context.getRecognizedIntent() != null) {
            switch (context.getRecognizedIntent().getType()) {
                case USER_LOGIN:
                case USER_REGISTRATION:
                case TASK_CREATION:
                    return false;
                default:
                    return true;
            }
        }
        
        return true;
    }
    
    /**
     * 判断响应结果是否可缓存
     * 
     * @param context 响应上下文
     * @param result 响应结果
     * @return 是否可缓存
     */
    private boolean isCacheable(ResponseContext context, ResponseResult result) {
        // 只缓存成功的响应
        if (!result.isSuccess()) {
            return false;
        }
        
        // 不缓存质量分数过低的响应
        if (result.getQualityScore() < 0.7) {
            return false;
        }
        
        // 不缓存包含时间敏感信息的响应
        if (result.getContent() != null) {
            String content = result.getContent().toLowerCase();
            if (content.contains("现在") || content.contains("当前") || 
                content.contains("今天") || content.contains("实时")) {
                return false;
            }
        }
        
        // 检查响应大小
        if (result.getContent() != null && result.getContent().length() > 10000) {
            return false; // 不缓存过大的响应
        }
        
        return true;
    }
    
    /**
     * 确定缓存TTL
     * 
     * @param context 响应上下文
     * @param result 响应结果
     * @return TTL（分钟）
     */
    private long determineTtl(ResponseContext context, ResponseResult result) {
        // 根据意图类型确定不同的TTL
        if (context.getRecognizedIntent() != null) {
            switch (context.getRecognizedIntent().getType()) {
                case TRAVEL_PLANNING:
                    return 60; // 出行规划缓存1小时
                case GENERAL_CHAT:
                    return 15; // 一般聊天缓存15分钟
                case HELP_REQUEST:
                    return 120; // 帮助信息缓存2小时
                default:
                    return defaultTtlMinutes;
            }
        }
        
        // 根据响应质量调整TTL
        if (result.getQualityScore() > 0.9) {
            return defaultTtlMinutes * 2; // 高质量响应缓存更久
        } else if (result.getQualityScore() < 0.8) {
            return defaultTtlMinutes / 2; // 低质量响应缓存时间减半
        }
        
        return defaultTtlMinutes;
    }
    
    /**
     * 清理过期的缓存条目
     */
    private void evictOldestEntries() {
        // 移除过期的条目
        cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
        
        // 如果还是超过限制，移除最老的条目
        if (cache.size() >= maxCacheSize) {
            String oldestKey = cache.entrySet().stream()
                    .min((e1, e2) -> e1.getValue().getCachedAt().compareTo(e2.getValue().getCachedAt()))
                    .map(java.util.Map.Entry::getKey)
                    .orElse(null);
            
            if (oldestKey != null) {
                cache.remove(oldestKey);
                logger.debug("移除最老的缓存条目: {}", oldestKey);
            }
        }
    }
    
    /**
     * 清空缓存
     */
    public void clearCache() {
        cache.clear();
        logger.info("缓存已清空");
    }
    
    /**
     * 获取缓存统计信息
     * 
     * @return 缓存统计
     */
    public CacheStats getCacheStats() {
        long expiredCount = cache.values().stream()
                .mapToLong(entry -> entry.isExpired() ? 1 : 0)
                .sum();
        
        return new CacheStats(
                cache.size(),
                expiredCount,
                maxCacheSize,
                enableCache
        );
    }
    
    /**
     * 设置缓存配置
     * 
     * @param ttlMinutes TTL（分钟）
     * @param maxSize 最大缓存大小
     * @param enabled 是否启用
     */
    public void configureCaching(long ttlMinutes, int maxSize, boolean enabled) {
        this.defaultTtlMinutes = ttlMinutes;
        this.maxCacheSize = maxSize;
        this.enableCache = enabled;
        
        logger.info("缓存配置已更新 - TTL: {}分钟, MaxSize: {}, Enabled: {}", 
                ttlMinutes, maxSize, enabled);
    }
    
    /**
     * 缓存条目内部类
     */
    private static class CacheEntry {
        private final ResponseResult result;
        private final LocalDateTime cachedAt;
        private final long ttlMinutes;
        
        public CacheEntry(ResponseResult result, long ttlMinutes) {
            this.result = result;
            this.cachedAt = LocalDateTime.now();
            this.ttlMinutes = ttlMinutes;
        }
        
        public boolean isExpired() {
            return ChronoUnit.MINUTES.between(cachedAt, LocalDateTime.now()) > ttlMinutes;
        }
        
        public ResponseResult getResult() {
            return result;
        }
        
        public LocalDateTime getCachedAt() {
            return cachedAt;
        }
        
        public long getTtlMinutes() {
            return ttlMinutes;
        }
    }
    
    /**
     * 缓存统计信息
     */
    public static class CacheStats {
        private final int totalEntries;
        private final long expiredEntries;
        private final int maxSize;
        private final boolean enabled;
        
        public CacheStats(int totalEntries, long expiredEntries, int maxSize, boolean enabled) {
            this.totalEntries = totalEntries;
            this.expiredEntries = expiredEntries;
            this.maxSize = maxSize;
            this.enabled = enabled;
        }
        
        public int getTotalEntries() { return totalEntries; }
        public long getExpiredEntries() { return expiredEntries; }
        public int getMaxSize() { return maxSize; }
        public boolean isEnabled() { return enabled; }
        public int getActiveEntries() { return (int) (totalEntries - expiredEntries); }
        public double getUsagePercentage() { return maxSize > 0 ? (double) totalEntries / maxSize * 100 : 0; }
        
        @Override
        public String toString() {
            return String.format("CacheStats{active=%d, expired=%d, total=%d, max=%d, usage=%.1f%%, enabled=%s}",
                    getActiveEntries(), expiredEntries, totalEntries, maxSize, getUsagePercentage(), enabled);
        }
    }
    
    /**
     * 创建包装指定生成器的缓存装饰器
     * 
     * @param generator 要包装的生成器
     * @return 缓存装饰器实例
     */
    public static CachingResponseDecorator wrap(ResponseGenerator generator) {
        return new CachingResponseDecorator(generator);
    }
}